#include "oled.h"
#include "font.h"


//extern SPI_HandleTypeDef hspi2;

uint8_t OLED_GRAM[128][8];

#if defined(HARD_IIC) || defined(GPIO_SIMU_IIC)
// 需实现delay_us()
#define DELAY_US(x) HAL_Delay_US(x)

void IIC_Start()
{
	SDA_OUT();
	OLED_SCL(1);
	OLED_SDA(1);
	DELAY_US(2);
	OLED_SDA(0);
	DELAY_US(2);
	OLED_SCL(0);
	DELAY_US(2);
}

void IIC_Stop()
{
	// SDA_OUT();
	OLED_SCL(1);
	OLED_SDA(0);
	DELAY_US(2);
	OLED_SDA(1);
	DELAY_US(2);
}

uint8_t IIC_Wait_Ask()
{
	uint16_t cnt=0;
	SDA_IN();
	OLED_SCL(1);
	DELAY_US(2);
	while (OLED_READ_SDA())
	{
		cnt++;
		if(cnt > 250){
			IIC_Stop();
			return 1;
		}
	}
	OLED_SCL(0);
	DELAY_US(2);
	return 0;
}

#endif

static void OLED_WByte(uint8_t data)
{
#if defined(HARD_SPI)
	HAL_SPI_Transmit(&hspi2, &data, 1, 1000);
#elif defined(GPIO_SIMU_SPI)
	uint8_t i;
	OLED_CS(0);
	for(i=0; i<8; ++i)
	{
		OLED_D0(0);
		OLED_D1(data& 0x80);
		OLED_D0(1);
		data <<= 1;
	}
	OLED_CS(1);
	OLED_RES(1);
#elif defined(HARD_IIC)

#elif defined(GPIO_SIMU_IIC)
	uint8_t i;
	SDA_OUT();
	for(i=0; i<8; ++i){
		OLED_SCL(0);
		DELAY_US(2);
		OLED_SDA(data & 0x80);
		OLED_SCL(1);
		DELAY_US(2);
		OLED_SCL(0);
		data <<= 1;
	}
#endif
}

static void OLED_WDat(uint8_t dat)
{
#if defined(HARD_SPI) || defined(GPIO_SIMU_SPI)
	OLED_DC(1);
	OLED_WByte(dat);
#elif defined(HARD_IIC) || defined(GPIO_SIMU_IIC)
	IIC_Start();
	OLED_WByte(0x78);
	IIC_Wait_Ask();
	OLED_WByte(0x40);	// reg addr
	IIC_Wait_Ask();
	OLED_WByte(dat);
	IIC_Wait_Ask();
	IIC_Stop();
#endif
}

static void OLED_WCmd(uint8_t cmd)
{
#if defined(HARD_SPI) || defined(GPIO_SIMU_SPI)
	OLED_DC(0);
	OLED_WByte(cmd);
#elif defined(HARD_IIC) || defined(GPIO_SIMU_IIC)
	IIC_Start();
	OLED_WByte(0x78);
	IIC_Wait_Ask();
	OLED_WByte(0x00);	// reg addr
	IIC_Wait_Ask();
	OLED_WByte(cmd);
	IIC_Wait_Ask();
	IIC_Stop();
#endif
}

static void OLED_RefreshGRAM(void)
{
	uint8_t i,n;
	for(i=0; i<8; ++i)
	{
		OLED_WCmd(0xB0+i);	//设置页地址（0~7）
		OLED_WCmd(0x00);	//设置显示位置—列低地址
		OLED_WCmd(0x10);	//设置显示位置—列高地址
		for(n=0; n<128; ++n)
			OLED_WDat(OLED_GRAM[n][i]);
	}
}

static void OLED_DrawPoint(uint8_t x, uint8_t y, uint8_t t)
{
	uint8_t pos, bx, tmp=0;
	if(x>127|| y>63)	return;//越界(unsigned必大于0)
	pos = 7-y/8;
	bx = y%8;
	tmp = 1<<(7-bx);
	if(t)
		OLED_GRAM[x][pos] |= tmp;
	else
		OLED_GRAM[x][pos] &= ~tmp;
}

void OLED_Init(void)
{
#if defined(HARD_SPI) || defined(GPIO_SIMU_SPI)
	OLED_RES(0);
	HAL_Delay(100);
	OLED_RES(1);
#elif defined(HARD_IIC) || defined(GPIO_SIMU_IIC)
	HAL_Delay(100);
#endif

	OLED_WCmd(0xAE); //关闭显示
	OLED_WCmd(0xD5); //设置时钟分频因子,震荡频率
	OLED_WCmd(0x80);   //[3:0],分频因子;[7:4],震荡频率
	OLED_WCmd(0xA8); //设置驱动路数
	OLED_WCmd(0X3F); //默认0X3F(1/64) 
	OLED_WCmd(0xD3); //设置显示偏移
	OLED_WCmd(0X00); //默认为0
	OLED_WCmd(0x40); //设置显示开始行 [5:0],行数.										    
	OLED_WCmd(0x8D); //电荷泵设置
	OLED_WCmd(0x14); //bit2，开启/关闭
	OLED_WCmd(0x20); //设置内存地址模式
	OLED_WCmd(0x02); //[1:0],00，列地址模式;01，行地址模式;10,页地址模式;默认10;
	OLED_WCmd(0xA1); //段重定义设置,bit0:0,0->0;1,0->127;
	OLED_WCmd(0xC0); //设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数
	OLED_WCmd(0xDA); //设置COM硬件引脚配置
	OLED_WCmd(0x12); //[5:4]配置	 
	OLED_WCmd(0x81); //对比度设置
	OLED_WCmd(0xEF); //1~255;默认0X7F (亮度设置,越大越亮)
	OLED_WCmd(0xD9); //设置预充电周期
	OLED_WCmd(0xf1); //[3:0],PHASE 1;[7:4],PHASE 2;
	OLED_WCmd(0xDB); //设置VCOMH 电压倍率
	OLED_WCmd(0x30); //[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc;
	OLED_WCmd(0xA4); //全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏)
	OLED_WCmd(0xA6); //设置显示方式;bit0:1,反相显示;0,正常显示	    						   
	OLED_WCmd(0xAF); //开启显示

	OLED_CLS();
}

void OLED_Fill(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t dot)
{
	uint8_t x,y;
	for(x=x1; x<=x2; ++x)
		for(y=y1; y<=y2; ++y)
			OLED_DrawPoint(x, y, dot);
	OLED_RefreshGRAM();
}

void OLED_CLS(void)
{
	OLED_Fill(0, 0, 127, 63, 0x00);
}

static void OLED_ShowChar(uint8_t x, uint8_t y, uint8_t chr, uint8_t size, uint8_t mode)
{
	uint8_t i,j,tmp;
	uint8_t y0 = y;
	uint8_t csize = (size/8 + ((size%8) ?1 :0)) * (size/2);
	chr = chr - ' ';
	
	for(i=0; i<csize; ++i)
	{
		switch(size)
		{
			case 12:	tmp = asc2_1206[chr][i]; break;
			case 16:	tmp = asc2_1608[chr][i]; break;
			case 24:	tmp = asc2_2412[chr][i]; break;
			default: return;
		}
		for(j=0; j<8; ++j)
		{
			OLED_DrawPoint(x, y, ((tmp&0x80) ?mode :!mode) );//mode:0,反白显示;1,正常显示	
			tmp <<= 1;
			++y;
			if((y - y0) == size)
			{
				y = y0;
				++x;
				break;
			}
		}
	}
}

#if 0
//static uint32_t myPow(uint8_t m, uint8_t n)
//{
//	uint32_t result = 1;
//	while(n--) result *= m;
//	return result;
//}

//void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size)
//{
//	uint8_t i, tmp;
//	uint8_t enshow=0;
//	for(i=0; i<len; ++i)
//	{
//		tmp = (num/myPow(10, len-1-i))%10;
//		if(enshow == 0 && i < len - 1)//前置空格
//		{
//			if(tmp == 0)
//			{
//				OLED_ShowChar(x+(size/2)*i, y, ' ', size, 1);
//				continue;
//			}
//			else
//				enshow=1;
//		}
//		OLED_ShowChar(x+(size/2)*i, y, '0'+tmp, size, 1);
//	}
//	
//}
#endif
void OLED_ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t size)
{
	if(x+(size/2)*len > 127 || y+size > 63) return;
	uint8_t i, tmpchr;
	uint32_t tmpnum = num;
	
	for(i=0; i<len; ++i)
	{
		tmpchr = '0' + tmpnum%10;
		tmpnum /= 10;
		OLED_ShowChar(x+(size/2)*(len-1-i), y, tmpchr, size, 1);
		if(tmpnum == 0) break;
	}
	OLED_RefreshGRAM();
}

void OLED_ShowString(uint8_t x, uint8_t y, const uint8_t *p, uint8_t size)
{
	while((*p<='~') && (*p>=' '))//合法
	{
		if(x > (128-(size/2)) )
		{
			x=0;
			y+=size;
		}
		if(y > (64-size) )
		{
			y=x=0;
			OLED_CLS();
		}
		
		OLED_ShowChar(x, y, *p, size, 1);
		x += size/2;
		++p;
	}
	OLED_RefreshGRAM();
}
